package com.agent.user.Service.impl;

import cn.hutool.core.util.RandomUtil;
import com.agent.commons.constants.MinIOConstants;
import com.agent.commons.errorcode.ErrorCode;
import com.agent.commons.errorcode.ServiceErrorCodeConstants;
import com.agent.commons.exception.BaseException;
import com.agent.commons.utils.*;
import com.agent.feign.entity.Member;
import com.agent.user.dto.PictureCodeDTO;
import com.agent.user.dto.UserLoginDTO;
import com.agent.user.entity.PictureCode;
import com.agent.user.mapper.UserMapper;
import com.agent.user.param.UserLoginParam;
import com.agent.user.param.UserParam;
import com.agent.user.Service.UserService;
import com.agent.user.vo.UserLoginVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import static com.agent.commons.constants.RedisConstants.*;

@Slf4j
@Service
public class UserviceImpl implements UserService {


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Override
    public UserLoginVO LoginByCode(UserLoginParam userLoginParam) {
        if (!RegexUtil.checkMail(userLoginParam.getEmail())) {
            throw new BaseException(ServiceErrorCodeConstants.MAIL_ERROR);
        }else{
            if(!checkAuth(userLoginParam.getEmail(),userLoginParam.getCode())){
                throw new BaseException(ServiceErrorCodeConstants.AUTH_ERROR);
            }
        }
        UserLoginDTO userLoginDTO = userMapper.LoginByCode(userLoginParam);
        if(userLoginDTO==null){
            if(userLoginParam.getEmail()!=null) {
                throw new BaseException(new ErrorCode(504, "邮箱或密码错误"));
            }else{
                throw new BaseException(new ErrorCode(504, "账号或密码错误"));
            }
        }
        String token = sendTokenMessage(userLoginParam);
        UserLoginVO userLoginVO = convertUserLoginVO(userLoginDTO);
        userLoginVO.setToken(token);
        return userLoginVO;
    }

    @Override
    public UserLoginVO LoginByPassword(UserLoginParam loginParam) {
        String encrypt = Sm4Util.encrypt(loginParam.getPassword());
        //进行账号与密码校验
        if(loginParam.getUserId()!=null) {
            if (!encrypt.equals(userMapper.getPasswordByUserId(loginParam.getUserId()))) {
                throw new BaseException(ServiceErrorCodeConstants.USER_ID_ERROR.getCode(), "账号或密码错误");
            }
        }else{
            if(!encrypt.equals(userMapper.getPasswordByEmail(loginParam.getEmail()))){
                throw new BaseException(ServiceErrorCodeConstants.USER_ID_ERROR.getCode(), "邮箱或密码错误");
            }
        }
        //密码进行加密
        loginParam.setPassword(encrypt);
        String token = sendTokenMessage(loginParam);
        UserLoginVO userLoginVO = convertUserLoginVO(userMapper.LoginByPassword(loginParam));
        userLoginVO.setToken(token);
        return userLoginVO;
    }

    @Override
    public void registerUser(UserParam user) {
        user.setUserId(generateId());
        if(user.getGender().equals(1)){
            //todo 设置男生头像
        }else{
            //todo 设置女生头像
        }
        if (user == null) {
            throw new BaseException(ServiceErrorCodeConstants.REGISTER_INFO_IS_EMPTY);
        }
        // 校验注册信息是否为空
        if (user.getRole() == null) {
            throw new BaseException(ServiceErrorCodeConstants.IDENTITY_IS_EMPTY);
        }
        // 校验邮箱格式 xxx@xxx.xxx
        if (!RegexUtil.checkMail(user.getEmail())) {
            throw  new BaseException(ServiceErrorCodeConstants.MAIL_ERROR);
        }
        // 校验密码
        if (!StringUtils.hasText(user.getPassword())) {
            throw new BaseException(ServiceErrorCodeConstants.PASSWORD_IS_EMPTY);
        }
        // 密码校验, 至少6位
        if (!RegexUtil.checkPassword(user.getPassword())) {
            throw new BaseException(ServiceErrorCodeConstants.PASSWORD_ERROR);
        }
        // 校验邮箱是否被使用
        if (checkMailUsed(user.getEmail())) {
            throw new BaseException(ServiceErrorCodeConstants.MAIL_USED);
        }
        // 验证码是否为空
        if (!StringUtils.hasText(user.getCode())) {
            throw new BaseException(ServiceErrorCodeConstants.AUTH_IS_EMPTY);
        }
        // 验证码是否正确
        if (!checkAuth(user.getEmail(), user.getCode())) {{
            throw new BaseException(ServiceErrorCodeConstants.AUTH_ERROR);
        }}
        //使用Sm4加密算法进行密码加密
        user.setPassword(Sm4Util.encrypt(user.getPassword()));
        userMapper.insertUser(user);
    }

    /**
     * 验证码发送
     * @param email
     * @return
     */
    @Override
    public Boolean getCode(String email) {
        if (RegexUtil.checkMail(email)) {
            // 生成验证码
            String code = RandomUtil.randomNumbers(6);
            // 存入redis
            String exchangeName = "direct.exchange";
            Map<String, Object> message = Map.of("email", email, "code", code );
            // 发送邮件
            RabbitMqUtil.sendMessageDirect(exchangeName, message, "code");
            // MailUtil.sendSampleMail(email,"注册验证码",code);
            return mailUtil.sendSampleMail(email,"验证码",code);
        }
        return false;
    }

    /**
     * 验证图片验证码
     * @param code
     * @return
     */
    @Override
    public Boolean checkPictureCode(PictureCode code) {
        String codeUrl=stringRedisTemplate.opsForValue().get(PICTURE_CODE+code.getCode());
        return codeUrl != null && codeUrl.equals(code.getUrl());
    }

    /**
     * 获取生成的图片路径以及code
     * @return
     */
    @Override
    public PictureCodeDTO generatePictureCode() {
        //生成包含验证码以及图片输出流的Map集合
        Map<String, ByteArrayOutputStream> captchaPicture = CaptchaUtil.createCaptchaPicture();
        PictureCodeDTO pictureCodeDTO=new PictureCodeDTO();
        captchaPicture.forEach((code,outputStream)->{
            pictureCodeDTO.setCode(code);
            //字节输出流转换为输入流
            ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
            try {
                pictureCodeDTO.setUrl(MinIOConstants.FILE_BEFORE+MinIOUtil.uploadFile("test-one",inputStream, UUID.randomUUID()+".png"));
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        //发送消息到Mq交换机
        RabbitMqUtil.sendMessageDirect("direct.exchange",pictureCodeDTO,"picture");
        return pictureCodeDTO;
    }

    /**
     * 获取班级成员相关信息
     * @param userId
     * @return
     */
    @Override
    public Member getMember(String userId) {
        return userMapper.getMember(userId);
    }

    private boolean checkMailUsed(String email) {
        int count = userMapper.countByMail(email);
        return count>0;
    }

    private boolean checkAuth(String email, String auth) {
        String ret = stringRedisTemplate.opsForValue().get(REGISTER_LOGIN_CODE+email);
        return auth.equals(ret);
    }

    /**
     * 实现token负载的转换，以及消息队列的投递
     * @param userLoginParam
     */
    private String sendTokenMessage(UserLoginParam userLoginParam){
        Map<String,Object> pleader  = new HashMap<>();
        Map<String,Object> payload = new HashMap<>();
        if(userLoginParam.getUserId()==null){
            userLoginParam.setUserId(userMapper.getUserIdByEmail(userLoginParam.getEmail()));
        }
        payload.put("userId",userLoginParam.getUserId());
        payload.put("userName",userMapper.getName(userLoginParam.getUserId()));
        payload.put("userRole",userMapper.getRole(userLoginParam.getUserId()));
        String token = JWTUtil.createJwt(payload);
        pleader.put("userId",userLoginParam.getUserId());
        pleader.put("token",token);
        rabbitTemplate.convertAndSend("direct.exchange","token",pleader);
        return token;
    }

    /**
     * UserLoginDTO->UserLoginVO
     * @param userLoginDTO
     * @return
     */
    private UserLoginVO convertUserLoginVO(UserLoginDTO userLoginDTO){
        UserLoginVO userVo = new UserLoginVO();
        userVo.setId(userLoginDTO.getId());
        userVo.setUserId(userLoginDTO.getUserId());
        userVo.setUserName(userLoginDTO.getUserName());
        userVo.setAvatar(userLoginDTO.getAvatar());
        userVo.setRole(userLoginDTO.getRole());
        return userVo;
    }
    /**
     * 给用户随机匹配id
     * @return
     */
    private String generateId(){
        //第一次随机生成id
        String userId=RandomUtil.randomNumbers(10);
        //判断是否有重复Id
        while(userMapper.countByUserId(userId)!=0){
            userId=RandomUtil.randomNumbers(10);
        }
        return userId;
    }
}
